/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

#ifndef LIB_INSIM
#define LIB_INSIM

#ifdef WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h
#define closesocket(s) close(s)
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
#endif
#include <time.h>
#include <stdio.h>

#include "insim.h"
#include "list.h"
#include "version.h"

#define INSIM_VERSION_TIMEOUT_MAX 10
#define INSIM_TIMEOUT 70
#define INSIM_TIMEOUT_MAX 120
#define INSIM_KEEPALIVE 30
#define INSIM_KEEPALIVE_MAX 60
#define PACKET_BUFFER_SIZE MAX_BUFFER_SIZE

struct socket_info_t
{
    /* socket */
    int s;
	/* How long before we timeout select */
	struct timeval select_timeout;
	/* How long before we assume we've lost network connectivity with LFS */
	unsigned int timeout;
};

struct lfs_info_t
{
	char *address;
	unsigned short port;
	char *admin_password;
	unsigned char flags;
	unsigned char node_secs;
	unsigned char prefix;
};

struct buffer_t
{
    /* packet buffer - 512 should be more than enough */
	char buffer[PACKET_BUFFER_SIZE];
	/* number of bytes currently in buffer */
	unsigned int bytes;
};

struct internals_t
{
    /* path for log files, etc. */
    char *path;
    /* number of connection attempts */
    unsigned int connection_attempts;
    /* fast connect */
    BOOL fast_connect;
    /* auto reconnect? */
    BOOL reconnect;
	/* Spam-factor */
	unsigned int verbose;
	/* do we quit, true = yes, false = no */
	BOOL quit;
	/* Version recv? */
	BOOL gotvers;
};

struct insim_t
{
    struct socket_info_t socket;
    struct lfs_info_t lfs;
    struct internals_t internals;
    struct buffer_t pbuf;
    // Hooks
    struct list_t *hooks;
};

// Structure of the hooks data
struct hooks_t
{
    // Name for identifying
    char name[32];
    // Context - pointer for hook allocatable memory
    void *ctx;
    // Function pointers
    // Create - use to allocate any memory required
    void (*fp_create)(struct insim_t *I, void **ctx);
    // Connected
    void (*fp_connected)(struct insim_t *I, void *ctx);
    // PreRecv
    void (*fp_prerecv)(struct insim_t *I, void *ctx);
    // Recv - called when a packet is received
    void (*fp_recv)(struct insim_t *I, void *ctx, void *data, unsigned int size);
    // Disconnected
    void (*fp_disconnected)(struct insim_t *I, void *ctx);
    // Close - use to free any memory, clean ups, etc
    void (*fp_close)(struct insim_t *I, void *ctx);
    // my include (repeat)
    void (*fp_thread)(struct insim_t *I, void *ctx);

};

struct insim_t *insim_create();
int insim_destroy(struct insim_t *I);

int insim_connect(struct insim_t *I);
int insim_recv(struct insim_t *I);
int insim_disconnect(struct insim_t *I);

int insim_send(struct insim_t *I, const char *buf, unsigned int size);

int insim_init(struct insim_t *I);
int insim_close(struct insim_t *I);

int insim_hook_fire_create(struct insim_t *I);
int insim_hook_fire_prerecv(struct insim_t *I);
int insim_hook_fire_recv(struct insim_t *I, void *data, unsigned int size);
int insim_hook_fire_close(struct insim_t *I);

int insim_hook_fire_connected(struct insim_t *I);
int insim_hook_fire_disconnected(struct insim_t *I);

#endif
